/** @noSelf **/
import {TimerModel} from "./apiModel/adapterModel/model2/TimerModel";
import {GlobalModel} from "./apiModel/adapterModel/model1/GlobalModel";
import MathUtil from "./codeAdapter/MathUtil";

export enum TimerType {
    low = 1,
    main,
    last,
}

export enum TimerStatus {
    nomal = 1,
    always,
    pasuse,
    end,
}

export class Timer {
    // 执行间隔
    interval: number;
    // 执行次数
    times: number;
    // 回调函数
    callBack: (this: void) => void;
    // 计时器状态
    status: TimerStatus;
    // 计时器类型
    type: TimerType;
    // 预计执行时间
    endTime: number;

    // 这些属性用于计时器暂停
    // 本次执行剩余时间
    leaveTime: number;
    startTime: number;
    // 上次启动 或 暂停 的时间
    lastPauseTime: number;

    pauseTime: number = 0;



    constructor(times: number, interval: number, status: TimerStatus, type: TimerType, callBack: (this: void) => void, startTime: number) {
        this.times = times;
        this.interval = interval
        this.leaveTime = interval;
        this.callBack = callBack;
        this.status = status;
        this.type = type;
        this.startTime = startTime;

        this.endTime = this.startTime + this.leaveTime
    }

    exeCallBack = (): boolean => {
        const currentTime = MathUtil.toFixed(TimerUtil.getGameTime(), 2);
        const endTime = MathUtil.toFixed(this.endTime, 2);
        if (endTime === currentTime) {
            const fun = this.callBack;
            fun && fun();
            this.startTime = TimerUtil.getGameTime();
            this.leaveTime = this.interval;
            this.endTime = this.startTime + this.leaveTime
            return true;
        }
        GlobalModel.toast(`${endTime}|${currentTime}`)
    }

    pause = () => {
        if (this.status === TimerStatus.nomal) {
            this.status = TimerStatus.pasuse
            // 暂停计时器时  计时器的剩余时间等于
            const currentTime = TimerUtil.getGameTime();
            this.leaveTime = this.interval - ( currentTime - this.startTime  - this.pauseTime );
            this.lastPauseTime = currentTime;
            return true;
        } else {
            GlobalModel.toast(`当前类型计时器 ${this.status} 不支持暂停`)
        }
    }

    resume = () => {
        if (this.status === TimerStatus.pasuse) {
            const currentTime = TimerUtil.getGameTime();
            const currentPauseTime = currentTime - this.lastPauseTime;

            this.pauseTime = this.pauseTime + currentPauseTime
            this.status = TimerStatus.nomal;
            this.endTime = currentTime + this.leaveTime
            GlobalModel.toast(`恢复计时器 ${this.leaveTime}`);
            GlobalModel.toast(`本次暂停 ${currentPauseTime}`);
            GlobalModel.toast(`总暂停 ${this.pauseTime}`);
            TimerUtil.addTimer(this);
            return true;
        }
    }

    end() {
        this.status = TimerStatus.end;
    }

}

export default class TimerUtil {

    /**
     *  基础中心计时器
     */
    //毫秒计算
    static time = 0;
    static timers: {
        // 类型计时器当前时间
        time: number;
        // 类型计时器暂停标识
        bPause: boolean;
        // 类型计时器所有方法，以推入计时器的时间为key
        timerMaps: { [time: string]: Timer[] };
    }[] = [];
    // static middleTimeCallBack: { [time: number]: ((this: void) => void)[] } = {};
    // static highTimeCallBack: { [time: number]: ((this: void) => void)[] } = {};

    /**
     *
     * @param timeOut 延迟的时间 （单位：秒）
     * @param callBack
     * @param loopCount
     */
    static runLater(timeOut: number, callBack: (this: void) => void, loopCount: number = 1, type: TimerType = TimerType.main, status: TimerStatus = TimerStatus.nomal) {
        const startTime = TimerUtil.getGameTime();
        const tempTimer = new Timer(loopCount, timeOut, status, type, callBack, startTime)

        TimerUtil.addTimer(tempTimer);

        return tempTimer;
    }

    static addTimer(tempTimer: Timer) {
        const type = tempTimer.type;
        const timeOut = MathUtil.floor(tempTimer.leaveTime * 1000);
        const timer = TimerUtil.timers[type - 1];

        const scopeTime = timer.time;
        let tempTime = scopeTime + (timeOut);
        const timerMaps = timer.timerMaps;
        let timersArr: Timer[] = timerMaps[`${tempTime}`];
        if (timersArr == null) {
            timersArr = []
            timerMaps[`${tempTime}`] = timersArr;
        }
        timersArr.push(tempTimer)
    }

    private static OnTime(this: void) {
        TimerUtil.time = TimerUtil.time + 10;
        for (let type = 0; type < TimerType.last; type++) {
            const timer = TimerUtil.timers[type];
            const bPause = timer.bPause;
            if (bPause) {
                continue;
            }
            timer.time = timer.time + 10;
            const scopeTime = timer.time;
            const timerMaps = timer.timerMaps;
            let timerArr = timerMaps[`${scopeTime}`];
            if (timerArr) {
            } else {
                continue;
            }
            for (let timer of timerArr) {
                if (timer) {
                    switch (timer.status) {
                        case TimerStatus.end:{
                            break;
                        }
                        case TimerStatus.pasuse:{
                            break;
                        }
                        case TimerStatus.nomal:
                        case TimerStatus.always: {
                            const ret = timer.exeCallBack();
                            if (ret) {
                                let needAdd = true;
                                if (timer.status === TimerStatus.nomal) {
                                    timer.times = timer.times - 1;
                                    if (timer.times <= 0) {
                                        timer.status = TimerStatus.end;
                                        needAdd = false;
                                    }
                                }
                                if (needAdd) {
                                    TimerUtil.addTimer(timer)
                                }
                            }
                            break;
                        }
                    }
                }
            }
            timerMaps[`${scopeTime}`] = null;
        }
    }

    //返回秒
    static getGameTime(): number {
        return TimerUtil.time / 1000;
    }

    static init() {
        for (let type = 0; type < TimerType.last; type++) {
            TimerUtil.timers[type] = { bPause: false, time: 0, timerMaps: {} };
        }
        new TimerModel('总线').start(0.01, true, TimerUtil.OnTime);
    }

}
